home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / inter52g.zip / INT2GUID.ZIP / INT2GUID.C < prev    next >
Text File  |  1994-03-19  |  25KB  |  814 lines

  1. /* INT2GUID.C
  2.  *
  3.  * from:
  4.  * INT2QH.C
  5.  *
  6.  * Author:   Kai Uwe Rommel
  7.  * Date:     Sun 07-Oct-1990
  8.  * Update:   Sat 20-Oct-1990
  9.  * Update:   Sun 11-Nov-1990  Ralf Brown
  10.  *
  11.  * Compiler: MS C 5.00 and newer / compact model, or TC 2.0 / compact model
  12.  * System:   PC/MS-DOS 3.20 and newer, OS/2 1.0 and newer
  13.  *
  14.  *
  15.  * INT2GUID.C is a GUIDE/MAKEHELP version of INT2QH.C. GUIDE and MAKEHELP
  16.  * are programs for pop-up help included the TurboPower Software package
  17.  * Turbo Professional.
  18.  *
  19.  * Transscriptor:    Bent Lynggaard
  20.  * Date:    1.00    Sun 24-Mar-1991
  21.  * Update:    1.01    Tue 02-Apr-1991    - test '!', ';' in line pos 1.
  22.  *                    - test disk full
  23.  *        1.02    Sun 14-Apr-1991    - smaller index pages
  24.  *                    - main index always leads to start of
  25.  *                      an INT #
  26.  *        1.03    Sun 12-May-1991    - configuration file.
  27.  *        1.04    Sat 18-May-1991 - conditional mask in *.cfg
  28.  *        1.05    Sun 29-Dec-1991 - fixed \n bug in configure()
  29.  *        1.06    Sun 09-May-1992 - adjusted for change in file format
  30.  *                    - "dividerline" info as headings
  31.  *                    - all registers can carry parameters
  32.  *        1.07    Sat 19-Dec-1992 - fixed bug (reading from closed file)
  33.  *                    - "dividerline" info as topics
  34.  *                    - "dividerline" char 9 function info
  35.  *                    - new subtopic criteria
  36.  *                    - program initialization in
  37.  *                        configuration file
  38.  *                    - splitting up long topics
  39.  *        1.08    Sun 04-Apr-1993 - topic # in "Missing divider line"
  40.  *                        to ease manual editing
  41.  *        1.09    Sat 03-Jul-1993 - fixed bug introduced in v. 1.07
  42.  *        1.10    Sat 19-Mar-1994 - [no]filter and help options
  43.  *
  44.  * This program creates output to the standard output device. The output
  45.  * should be redirected to a file INTERRUP.TXT. The created file should
  46.  * be compiled by the TurboPower MAKEHELP program to a INTERRUP.HLP file,
  47.  * which can be interpreted by the TurboPower GUIDE TSR program:
  48.  *    INT2GUID > [ramdisk:]INTERRUP.TXT
  49.  *    MAKEHELP [ramdisk:INTERRUPT] INTERRUP[.HLP] /Q
  50.  *    GUIDE INTERRUP    (or enter GUIDE with a hot key, press F3,
  51.  *            enter INTERRUP)
  52.  *
  53.  * TurboPower Software supplies a program called POPHELP in their Object
  54.  * Professional package, which is a successor to GUIDE. INT2GUID has
  55.  * facilities for conditional interpretation of supplementary files, so
  56.  * these files can include code optimized for both GUIDE and POPHELP, and
  57.  * the parts compiled depends on a mask defined in the configuration file.
  58.  *
  59.  * The following is considered in creating the topic (and popup window)
  60.  * headers:
  61.  * The first word in the header is the interrupt number, so that GUIDE's
  62.  * search mechanism can find the entry if the hot key is pressed when
  63.  * the cursor is at an interrupt number.
  64.  * MAKEHELP restricts the (length of longest header + 1) times the number
  65.  * of topics to 64 kB. INTER191 had about 2200 topics, so the length of
  66.  * the headers should be limited to 25 characters. However, rather than
  67.  * truncating the INTERRUP.LST header lines to some nonsense, this
  68.  * program uses only the interrupt number as topic headings, plus the
  69.  * AH or AX values where applicable.
  70.  * (v. 1.06: "divider line" info (e.g. "214C" in "--------214C------...")
  71.  * is used for headings, thus allowing a more selective search by GUIDE's
  72.  * cursor-word search.)
  73.  * The main index references some subindeces. The subindeces use the
  74.  * MAKEHELP cross reference facility. MAKEHELP limits the number of cross
  75.  * references to 50 per topic, however, this program limits each subindex
  76.  * to 18 entries, so each "topic" can be shown on one single screen with
  77.  * height 20 lines. For each interrupt number, the entries are temporarily
  78.  * stored, and written to the current subindex page only if all entries
  79.  * for the interrupt number fit on the page.
  80.  *
  81.  * MAKEHELP's text wrapping mechanism is disabled, and as the active
  82.  * window is limited to 76 characters, some lines are missing one or two
  83.  * characters.
  84.  * The amount of text that can be displayed per topic is limited by
  85.  * GUIDE's setting of pages/topic (default = 20) and the screen height
  86.  * defined when GUIDE was initialized.
  87.  *
  88.  */
  89.  
  90. #define LABEL    "int2guid.c"
  91. #define VERSION  "1.10"
  92.  
  93. #include <stdio.h>
  94. #include <stdlib.h>
  95. #include <string.h>
  96. #include <ctype.h>
  97.  
  98. #define divider_line(s) (strncmp(s,"--------",8)==0)
  99. #define maxIndeces 18
  100.   /* max 50, 18 gives one page with height 20 (18 active lines) */
  101. #define mainIndex 200
  102.   /* 1-99 reserved for program, 100-199 reserved for user */
  103. /* NB! The value 200 is used as text in main() after Topic 2 and in
  104.    file INT2GUID.REF.
  105. */
  106. #define false 0
  107. #define true 1
  108.  
  109. FILE *input, *output, *topics, *subtopics, *config;
  110.  
  111. char line1[128];
  112. char line2[128];
  113. char configline[128];
  114. char tempBuffer[50 * 128];
  115. char *tempPtr;
  116. char category[4] = "--";
  117. char nextHeader[16] = "??"; /* v. 1.07: 16 rather than 14 */
  118. char infilename[14] = "interrup.lst";
  119. #define infileExt 9
  120. int splitInfile = 0;
  121. int classification = 0;
  122. int WIDTH = 80;
  123.   /* WIDTH is the screen with for GUIDE/POPHELP. 80 is the best choice for
  124.      GUIDE, 78 is the best choice for POPHELP (which does not count the
  125.      frame as a part of the screen). The configuration file can change
  126.      this value. v. 1.07.
  127.   */
  128. long topicStart = 0; /* v. 1.07 */
  129. unsigned maxTopicLength = 32000; /* v. 1.07 */
  130.   /* texts longer than maxTopicLength are split into two or more topics.
  131.      The configuration file can change this value.
  132.   */
  133. char currentHeader[16]; /* v. 1.07 */
  134.  
  135. char configfile[14] = "int2guid.cfg";
  136. char configmarker[18] = "INT2GUIDE CONFIG";
  137.  
  138. char missingFile[] = "Missing include file.";
  139.  
  140. int sub = 0, indexed = 1;
  141. int filter = 1; /* v. 1.10, suggest filtering */
  142. char filterFileName[120] = ""; /* v. 1.10 */
  143. FILE *filterFile; /* v. 1.10 */
  144. unsigned currentID = 1, activeID = 1, indeces = 0, indexNo = 0, buffered = 0,
  145.   subindeces, activeSub, mask;
  146. int headerlength; /* v. 1.07 */
  147. unsigned reservedID = mainIndex; /* v. 1.07 */
  148.   /* reservedID reserves some topic numbers for long texts that are split
  149.      into more than one topic. currentID must then be incremented via a
  150.      function call in order to skip the reserved topics.
  151.   */
  152.  
  153. void usage(void) /* v. 1.10 */
  154. {
  155.   fputs(
  156.   "\n"
  157.   "INT2GUID transcribes information in Ralf Brown's Interrupt files to input for\n"
  158.   "TurboPower Software's MAKEHELP program for the GUIDE or POPHELP TSR programs.\n"
  159.   "\n"
  160.   "Use one of the forms:\n"
  161.   "    INT2GUID -?                 displays this help\n"
  162.   "    INT2GUID -nofilter          for a transcription of the entire list\n"
  163.   "    INT2GUID -f<filter file>    for a partial transcription\n"
  164.   "\n"
  165.   "INT2GUID reads input from one input file INTERRUP.LST, or from multiple input\n"
  166.   "files INTERRUP.A and successive extensions .B, .C, ..., and writes output to\n"
  167.   "stdout. The output can be redirected to a file.\n"
  168.   "\n"
  169.   "The program requires either the parameter \"-nofilter\" to specify that the\n"
  170.   "transcription includes all the information in Ralf Brown's Interrupt List, or\n"
  171.   "\"-f\" immediately followed by the name of an INTPRINT filter file to specify a\n"
  172.   "partial transcription. The information is used to include the right copyright\n"
  173.   "information in the program's output. The contents of a filter file is included\n"
  174.   "in the output.\n"
  175.   , stderr);
  176.   exit(0);
  177. } /* usage */
  178.  
  179. void exitfunc(void)
  180. {
  181.   fcloseall();
  182.   unlink("topic.tmp");
  183.   unlink("subtopic.tmp");
  184. }
  185.  
  186. void errorexit(char *msg)
  187. /* writes msg to stderr and exits with error code 1 */
  188. {
  189.   fputs(msg, stderr);
  190.   fputs("\n", stderr);
  191.   exit(1);
  192. } /* errorexit */
  193.  
  194. void explain(char *s)
  195. {
  196.   fputs("\7\n", stderr);
  197.   fputs(s, stderr);
  198.   errorexit("\n\nUse \"INT2GUID -?\" for help.");
  199. } /* explain */
  200.  
  201. void diskFull(int temporary)
  202. /* reports disk full and exits */
  203. {
  204.   char msg[80];
  205.   sprintf(msg,"\n\nDisk full, %s file\n", temporary ? "temporary" : "output");
  206.   errorexit(msg);
  207. } /* diskFull */
  208.  
  209.  
  210. int _fputs(char *line, FILE *stream)
  211. /* filters TABs to spaces, and inserts a leading space in lines starting
  212.    with the MAKEHELP command and comment characters '!' and ';'. "_fputs"
  213.    should be used when copying from unknown sources. Use "fputs" when
  214.    copying files with information specifically for this program.
  215. */
  216. {
  217.   char buffer[128];
  218.   int cnt = 0;
  219.  
  220.   if ( (*line=='!') || (*line==';') ) /* MAKEHELP command/comment? */
  221.     buffer[cnt++] = ' '; /* start with a space */
  222.  
  223.   while ( *line )
  224.   {
  225.     switch ( *line )
  226.     {
  227.       case '\t': do buffer[cnt++] = ' '; while ( cnt & 7 ); break;
  228.             /* MAKEHELP does not interpret tabs */
  229.       default  : buffer[cnt++] = *line;
  230.     }
  231.     line++;
  232.   }
  233.  
  234.   buffer[cnt] = 0;
  235.  
  236.   if ( (cnt = fputs(buffer, stream)) == EOF )
  237.     diskFull(stream != output);
  238.  
  239.   return cnt;
  240. }
  241.  
  242. char *_fgets(char *s, int n, FILE *stream)
  243. {
  244.   char *ptr;
  245.   ptr = fgets(s, n, stream);
  246.   if ( (ptr==NULL) && (stream==input) ) /* v. 1.09: edited */
  247.   {
  248.     fclose(input); /* 1.09: also unsplit file must be closed */
  249.     input=NULL;
  250.     if ( splitInfile )
  251.     {
  252.       infilename[infileExt]++;
  253.       input = fopen(infilename, "r");
  254.       if ( input != NULL )
  255.       {
  256.     fprintf(stderr, "%s\n", infilename);
  257.     ptr = fgets(s, n, input);
  258.       }
  259.     }
  260.   }
  261.   return ptr;
  262. } /* _fgets */
  263.  
  264. void Initialize(void)
  265. {
  266.   input     = fopen(infilename, "r");
  267.   if ( input == NULL )
  268.   {
  269.     infilename[infileExt] = 'a';
  270.     infilename[infileExt+1] = 0;
  271.     input = fopen(infilename, "r");
  272.     if ( input == NULL )
  273.     {
  274.       fputs("Cannot open input file (INTERRUP.LST or INTERRUP.A)\n", stderr);
  275.       exit(1);
  276.     }
  277.     splitInfile = 1;
  278.   }
  279.   fprintf(stderr, "%s\n", infilename);
  280.   output    = stdout;
  281.   topics    = fopen("topic.tmp", "w");
  282.   subtopics = fopen("subtopic.tmp", "w");
  283.  
  284.   tempPtr = tempBuffer;
  285.  
  286.   fprintf(output,
  287.     ";INTERRUPT help text for MAKEHELP/GUIDE.\n;\n!WIDTH %u\n;\n",WIDTH);
  288.     /* v. 1.07: WIDTH  rather than constant 80. WIDTH is initialized to 80
  289.        and can be changed in the configuration file.
  290.     */
  291.   fprintf(topics, "!TOPIC 1 Interrupt List\n!INDEX %u\n", mainIndex);
  292. }
  293.  
  294. int incrementID(void)
  295. /* v. 1.07: introduced in order to skip reserved IDs when incrementing currentID */
  296. {
  297.   ++currentID;
  298.   if (currentID == mainIndex)
  299.     currentID = reservedID;
  300.   return currentID;
  301. } /* incrementID */
  302.  
  303. void testTopic(void) /* limit xrefs/topic to maxIndeces */
  304. {
  305.   if ( indeces+buffered >= maxIndeces ) /* leave one entry for forw. ref */
  306.   {
  307.     incrementID();
  308.     fprintf(topics, "\004%u\005INT %s\005 (index continued)\n"
  309.       "!TOPIC %u INT %s (cont)\n!INDEX %u\n"
  310.       "(continued \004%u\005from\005)\n",
  311.       currentID, category, currentID, category, ++indexNo, activeID);
  312.     indeces = 1; /* the backwards ref */
  313.     activeID = currentID;
  314.   }
  315. } /* testTopic */
  316.  
  317. void copyBuffer(void)
  318. {
  319.   if ( buffered == 0 )
  320.     return;
  321.  
  322.   testTopic();
  323.   if ( fputs(tempBuffer, topics) == EOF )
  324.       diskFull(true);
  325.   indeces += buffered;
  326.   buffered = 0;
  327.   tempPtr = tempBuffer;
  328. } /* copyBuffer */
  329.  
  330. void Cleanup(void)
  331. {
  332.   copyBuffer();
  333.   fclose(topics);
  334.   fclose(subtopics);
  335.   fputs("Cleaning up\n", stderr);
  336.  
  337.   topics = fopen("topic.tmp", "r");
  338.   subtopics = fopen("subtopic.tmp", "r");
  339.  
  340.   while ( fgets(line1, sizeof(line1), topics) )
  341.     if ( fputs(line1, output) == EOF )
  342.       diskFull(false);
  343.  
  344.   while ( fgets(line1, sizeof(line1), subtopics) )
  345.     if ( fputs(line1, output) == EOF )
  346.       diskFull(false);
  347. } /* Cleanup */
  348.  
  349. void putAndCount(int putFunc(), char *line)
  350. /* split topic if maxTopicLength is exceeded. v. 1.07 */
  351. {
  352.   int ID, rID;
  353.   if ((ftell(output) - topicStart) > maxTopicLength)
  354.   {
  355.     ID = currentID;
  356.     rID = (reservedID > currentID) ? reservedID++ : ++currentID;
  357.     if (fprintf(output,"\004%u\005(text continues)\005\n"
  358.       "!TOPIC %u %s\n!NOINDEX\n"
  359.       "\004%u\005(text continued from)\005\n",
  360.       rID, rID, currentHeader, ID) == EOF)
  361.     diskFull(false);
  362.     topicStart = ftell(output);
  363.   }
  364.   if (putFunc(line, output) == EOF)
  365.     diskFull(false);
  366. } /* putAndCount */
  367.  
  368. int CopyFile(char *name, int commands)
  369. /* copies a file to the database, returns 0 for success or 1 for error */
  370.  
  371. /* If commands!=0, also interprets lines starting with "!! <number>" as
  372.    an update to variable "condition", and copies lines to the database
  373.    only if condition == 0 or (condition & mask) != 0
  374. */
  375. {
  376.   int condition = 0;
  377.   FILE *temp = fopen(name, "r");
  378.   char s[128];
  379.   fprintf(stderr, "%s\n", name);
  380.   if ( temp == NULL )
  381.   {
  382.     fprintf(stderr, "WARNING: Could not open %s\n", name);
  383.     fputs("Information was not available\n", output);
  384.     return 1;
  385.   }
  386.   else
  387.   {
  388.     while ( fgets(line2, sizeof(line2), temp) )
  389.       if ( !commands )
  390.     putAndCount(_fputs, line2);
  391.       else
  392.     /* does line start with "!! <number>" ? */
  393.     if ( sscanf(line2, "!!%i", &condition) != 1 )
  394.       /* yes: condition updated, sscanf returns 1 */
  395.       if ( (condition==0) || (condition & mask) )
  396.       {
  397.         if (sscanf(line2, "!%s", s) == 1)
  398.           if (strcmp(strupr(s), "TOPIC") == 0)
  399.             topicStart = ftell(output);
  400.         putAndCount(fputs, line2);
  401.       }
  402.     fputs("!NOWRAP\n", output); /* in case it was left in !WRAP state */
  403.     fclose(temp);
  404.     return 0;
  405.   }
  406. } /* CopyFile */
  407.  
  408. void testTemp(void)
  409. /* v. 1.06: allow no more than 50 entries in tempBuffer */
  410. /* v. 1.07: allow no more than 48 entries in tempBuffer */
  411. {
  412.   if (buffered >= 48)
  413.   {
  414.     copyBuffer();
  415.     fprintf(stderr,"INT %s has more than 48 subtopics and therefore more than one entry\n"
  416.       "in the main index (topic %u).\n", category, currentID);
  417.   }
  418. } /* testTemp */
  419.  
  420. void testSubtopic(char *marker)
  421. {
  422.   if ( ++subindeces >= maxIndeces )
  423.   {
  424.     testTemp();
  425.     sprintf(tempPtr, "\004%u\005%s\005  (list cont.)\n",
  426.       incrementID(), marker);
  427.     tempPtr += strlen(tempPtr);
  428.     buffered++;
  429.     fprintf(subtopics,
  430.       "\004%u\005%s\005  (list cont.)\n!TOPIC %u %s (list cont)\n!NOINDEX\n"
  431.       "(continued \004%u\005from\005)\n",
  432.       currentID, marker, currentID, category, activeSub);
  433.       activeSub = currentID;
  434.     subindeces = 2;
  435.   }
  436. } /* testSubtopic */
  437.  
  438.  
  439. void StartTopic(char *header, char *marker, char *desc)
  440. {
  441.   topicStart = ftell(output); /* v. 1.07 */
  442.   strncpy(currentHeader, header, sizeof(currentHeader));
  443.   currentHeader[sizeof(currentHeader)-1] = 0;
  444.   if (sub)
  445.   {
  446.     testSubtopic(marker);
  447.     if ( fprintf(subtopics, "\004%u\005%s\005  %s",
  448.       incrementID(), marker, desc) == EOF )
  449.     diskFull(true);
  450.     if (fprintf(output, "\004%u\005INT %s\005 (continued)\n",
  451.       currentID, category) == EOF)
  452.         diskFull(false);
  453.     /* insert a reference to this one in the former topic */
  454.   } /* if (sub) */
  455.   else
  456.   {
  457.     testTemp();
  458.     sprintf(tempPtr, "\004%u\005%s\005  %s", incrementID(), marker, desc);
  459.     tempPtr += strlen(tempPtr);
  460.     buffered++;
  461.   } /* else */
  462.  
  463.   fprintf(output, "!TOPIC %u %s\n", currentID, header);
  464.   if ( indexed )
  465.     indexNo++;
  466.   fprintf(output, indexed ? "!INDEX %u\n" : "!NOINDEX\n", indexNo);
  467. } /* StartTopic */
  468.  
  469. void StartList(void)
  470. /* v. 1.07: reorganized and edited */
  471. {
  472.   fprintf(subtopics, "!TOPIC %u %s (list)\n!NOINDEX\n", incrementID(), category);
  473.   if (fputs(tempBuffer, subtopics) == NULL)
  474.     diskFull(true); /* copy one entry in buffer to subtopics */
  475.   sub = 1;
  476.   subindeces = 1;
  477.   activeSub = currentID;
  478.   tempPtr = tempBuffer; /* reset buffer pointer */
  479.   buffered = 1; /* the entry we are going to use now */
  480.   sprintf(tempPtr, "\004%u\005%s\005  (list)\n", currentID, category);
  481.   tempPtr += strlen(tempPtr);
  482. } /* StartList */
  483.  
  484. /* void EndList(void) - not used */
  485.  
  486. /* char *NextID(void) - not used */
  487.  
  488. int RecognizedTopic(void)
  489. {
  490. /* v. 1.07: revised to use newheader info for marker string rather than
  491.    interpreting lines 1 and 2, and to use subtopics when there is more
  492.    than one entry rather than when there are entries with parameters.
  493. */
  494.   char *ptr, *pdesc, topic[4], marker[20];
  495.  
  496.   if (input == NULL)
  497.     return 0; /* v. 1.07: check input == NULL rather than read second line */
  498.  
  499.   if ( (pdesc = strchr(line1, '-')) == NULL )
  500.     pdesc = "(description not found)\n";
  501.  
  502.   if (headerlength==0) /* if info was missing in the dividerline */
  503.   { /* take INT # from line1[4]-[5] */
  504.     strncpy(nextHeader, &line1[4], 2);
  505.     nextHeader[2] = '\0';
  506.     fprintf(stderr,"Missing divider line info in topic %u:\n%s",
  507.       currentID, line1); /* 1.08: edited */
  508.   }
  509.   strncpy(topic, nextHeader, 2); /* interrupt number */
  510.   topic[2] = '\0';
  511.  
  512.   if ( strcmp(category, topic) )
  513.   {
  514.     sub = 0;
  515.     copyBuffer();
  516.     strcpy(category, topic);
  517.     fprintf(stderr, "%s\015", topic); /* show progress */
  518.   }
  519.   else
  520.   {
  521.     if (sub==0) /* v. 1.07 */
  522.       StartList();
  523.     /* v. 1.07: insert reference was moved to StartTopic */
  524.   }
  525.  
  526.   strcpy(marker, nextHeader); /* v. 1.07: use nextHeader for marker */
  527.   /* nextheader format: IIAHALXXNNNN_F (_F only if headerlength<0 */
  528.   /* marker format: II AHAL XXNNNN F */
  529.   if (headerlength < 0)
  530.   {
  531.     headerlength = abs(headerlength);
  532.     marker[headerlength-2] = ' '; /* '_' to space */
  533.   }
  534.  
  535.   if (headerlength > 2)
  536.   {
  537.     for (ptr = marker+headerlength+1; ptr >= &marker[2]; ptr--)
  538.       ptr[1] = *ptr;
  539.     /* memcpy(&marker[3], &marker[2], headerlength - 1);
  540.        did not work properly (compiler direction handling error)
  541.     */
  542.     marker[2] = ' ';
  543.     if (headerlength > 6+2)
  544.     {
  545.       for (ptr = marker+headerlength+2; ptr >= &marker[7]; ptr--)
  546.     ptr[1] = *ptr;
  547.       /* memcpy(&marker[8], &marker[7], headerlength - 5);
  548.         again. compiler error
  549.       */
  550.       marker[7] = ' ';
  551.       ptr = &marker[6];
  552.       while (*ptr == '_')
  553.     *ptr-- = ' '; /* spaces for AL or AX if unused */
  554.     } /* if (headerlength > 6+2) */
  555.   } /* if (headerlength > 2) *
  556.  
  557. /* v. 1.06: use global "nextHeader" rather than local "header" */
  558. /* v. 1.07: local "header" deleted */
  559.   StartTopic(nextHeader, marker, pdesc);
  560.  
  561.   _fputs(line1, output);
  562.  
  563.   return 1;
  564. } /* RecognizedTopic */
  565.  
  566. void CopyTopic(void)
  567. {
  568. /* v. 1.07: edited to split long texts into two or more topics */
  569.   char *ptr, *ptr2;
  570.  
  571.   for (;;)
  572.   {
  573.     if ( _fgets(line1, sizeof(line1), input) == NULL )
  574.       break;
  575.  
  576.     if ( !divider_line(line1) )
  577.       putAndCount(_fputs, line1);
  578.     else
  579.     {
  580.       if ( _fgets(line2, sizeof(line2), input) == NULL )
  581.     break;
  582.  
  583.       if ( strncmp(line2, "INT ", 4) )
  584.       {
  585.     putAndCount(_fputs, line1);
  586.     putAndCount(_fputs, line2);
  587.       }
  588.       else
  589.       {
  590.     /* v. 1.06: store divider line info as a header */
  591.     /* v. 1.07: edited */
  592.     strncpy(nextHeader, line1+10, 12);
  593.     for (ptr=nextHeader+11; *ptr=='-'; ptr--)
  594.       ;
  595.     if (ptr>&nextHeader[4])
  596.       for (ptr2=&nextHeader[2]; ptr2<ptr && ptr2<&nextHeader[6]; ptr2++)
  597.         if (*ptr2 == '-')
  598.           *ptr2 = '_';
  599.     headerlength = ptr - nextHeader + 1;
  600.     if (classification && line1[8]!='-')
  601.     {
  602.       *++ptr='_'; /* add char. 9 function classification */
  603.       *++ptr=line1[8];
  604.       headerlength = -headerlength-2;
  605.     }
  606.     *++ptr=0;
  607.     strcpy(line1, line2);
  608.     break;
  609.       } /* else */
  610.     } /* else */
  611.   } /* for (;;) */
  612. } /* CopyTopic */
  613.  
  614. void configError(void)
  615. {
  616.   errorexit("\nFormat error in configuration file.\n");
  617. } /* configError */
  618.  
  619. void readconfig(void)
  620. /* reads one line from file config to configline */
  621. {
  622.   if ( fgets(configline, sizeof(configline), config) == NULL )
  623.     configError();
  624. } /* readconfig */
  625.  
  626. void openconfig(void)
  627. /* opens configuration file and reads the initial part up to a line starting
  628.    with "=". This code defines how the initial lines are interpreted.
  629.    v. 1.07 defines:
  630.    configline[0] == '=': end of initial part
  631.    configline[0] == ';': comment
  632.    configline[0] == 'W': assign value to WIDTH
  633.    configline[0] == 'M': assign value to maxTopicLength
  634.    configline[0] == 'C': assign true to classification
  635.    The definitions are case sensitive.
  636. */
  637. {
  638.   int confv, confsubv;
  639.   char dummy[128];
  640.   config = fopen(configfile, "r");
  641.   if ( config == NULL )
  642.   {
  643.     fputs("\nWarning: No configuration file.\n", stderr);
  644.     return;
  645.   }
  646.   readconfig();
  647.   if (strncmp(configline, configmarker, strlen(configmarker)))
  648.     configError();
  649.   readconfig();
  650.   if (sscanf(configline, "%u%u", &confv, &confsubv) < 2)
  651.     configError();
  652.   if ((confv = ((confv << 8) + confsubv)) < 0x104)
  653.     errorexit ("\nThe configuration file is incompatible with this"
  654.     " version of INT2GUID");
  655.   if (confv < 0x107)
  656.     return;
  657.   while (!feof(config))
  658.   {
  659.     readconfig();
  660.     switch (configline[0])
  661.     {
  662.       case '=': return; /* done */
  663.       case ';': break; /* comment */
  664.       case 'W':
  665.       case 'M':
  666.     if ( sscanf(configline, "%s%u", &dummy,
  667.       configline[0]=='W' ? &WIDTH : &maxTopicLength) < 2 )
  668.       configError();
  669.     break;
  670.       case 'C': classification = true; break; /* include classification */
  671.       default: fprintf(stderr, "\nWARNING: Error in configuration file:\n%s",
  672.     configline);
  673.     } /* switch */
  674.   } /* while */
  675. } /* openconfig */
  676.  
  677. void copyline(char *str, int len)
  678. /* copies configline (after deleting the terminating '\n') to str
  679.     for max len characters. */
  680. {
  681.   configline[strlen(configline)-1] = 0; /* ignore '\n' */
  682.   strncpy(str, configline, len);
  683.   str[len] = 0; /* edited: v. 1.05 */
  684. } /* copyline */
  685.  
  686. void configure(void)
  687. /* parses configuration file */
  688. {
  689. #define maxHeader 14
  690. #define markerLen 12
  691.   int command, extraTopics, i;
  692.   char header[(maxHeader+2) & 0xFE], marker[(markerLen+2) & 0xFE],
  693.     desc[(76-markerLen) & 0xFE], filename[80];
  694.   /* v. 1.07: initial part moved to openconfig() */
  695.   while ( !feof(config) )
  696.   {
  697.     while ( (fgets(configline, sizeof(configline), config) != NULL)
  698.       && (configline[0] == ';') ) ;
  699.     if feof(config) break;
  700.     copyline(filename, 79);
  701.     readconfig();
  702.     copyline(header, maxHeader);
  703.     readconfig();
  704.     copyline(marker, markerLen);
  705.     i = strlen(marker);
  706.     while ( i<markerLen-1 ) /* pad with spaces if short */
  707.       marker[i++] = ' '; /* is already 0-terminated at markerLen */
  708.     readconfig();
  709.     copyline(desc, 76-markerLen-2);
  710.     i = strlen(desc); /* edited: v. 1.05 */
  711.     desc[i] = '\n';
  712.     desc[++i] = 0;
  713.     readconfig();
  714.     if ( sscanf(configline, "%u%u%i", &command, &extraTopics, &mask) < 3 )
  715.       configError();
  716.  
  717.     StartTopic(header, marker, desc);
  718.     CopyFile(filename, command);
  719.     currentID += extraTopics;
  720.   }
  721.   fclose(config);
  722. #undef maxHeader
  723. #undef markerLen
  724. } /* configure */
  725.  
  726. void main(int argc, char *argv[])
  727. {
  728.   int i;
  729.  
  730.   setcbrk(1);
  731.   fprintf(stderr, "\nINT2GUID %s - (c) Kai Uwe Rommel/Bent Lynggaard - %s\n",
  732.     VERSION, __DATE__);
  733.  
  734.   /* start of v. 1.10 update */
  735.   for (i=1; i<argc; i++) {
  736.     if (argv[i][0] == '-' || argv[i][0] == '/') {
  737.       if (!stricmp(&argv[i][1],"nofilter")) filter = 0;
  738.       else if (toupper(argv[i][1]) == 'F')
  739.     strcpy(filterFileName, &argv[i][2]);
  740.       else if (argv[i][1] == '?') usage();
  741.       else goto paramError;
  742.     } /* if (argv...) */
  743.     else
  744.   paramError:
  745.       explain("Illegal parameter.");
  746.   } /* for (i=0; ...) */
  747.  
  748.   if (filter && *filterFileName==0)
  749.     explain("INT2GUID must have parameter \"-nofilter\" or \"-f<filename>\".");
  750.  
  751.   if (filter) {
  752.     if ((filterFile = fopen(filterFileName, "r")) == NULL)
  753.       explain("Couldn't open filter file.");
  754.     fclose(filterFile);
  755.     reservedID++; /* topic mainIndex (200) is used for the filter file topic */
  756.   } /* if (filter) */
  757.   /* end of v. 1.10 update */
  758.  
  759.   atexit(exitfunc);
  760.  
  761.   openconfig();
  762.  
  763.   Initialize(); /* uses topic 1 */
  764.  
  765.   fputs("Including:\n",stderr);
  766.   StartTopic("Copyright etc.", "Copyright  ", "and references.\n");
  767.   if (filter) /* v. 1.10 */
  768.     mask = 2;
  769.   else
  770.     mask = 1;
  771.   if ( CopyFile("int2guid.ref", true) ) /* topic 2 */
  772.     errorexit(missingFile);
  773.   mask = 0;
  774.  
  775.   if (filter) { /* v. 1.10 */
  776.     topicStart = ftell(output);
  777.     if (fputs("!TOPIC 200 Filter File\n", output) == EOF)
  778.     /* here is a reference to 200, the value of mainIndex */
  779.       diskFull(false);
  780.     if (CopyFile("int2guid.re2", true))
  781.       errorexit(missingFile);
  782.     fputc('\1',output); /* toggle GUIDE/POPHELP attribute 1 */
  783.     if (CopyFile(filterFileName, false))
  784.       errorexit(missingFile);
  785.     fputs("\1\n",output); /* toggle attribute 1 back to normal */
  786.   } /* if (filter) */
  787.  
  788.   StartTopic("INTERRUP.LST", "HEADER     ", "Overview of the Interrupt List\n");
  789.   fputs("(See also \4""4\5INTERRUP.1ST\5)\n", output); /* insert reference */
  790.   CopyTopic(); /* topic 3 */
  791.  
  792.   StartTopic("INTERRUP.1ST", "Mail etc.  ", "How to get/update INTERRUP.LST\n");
  793.   if ( CopyFile("interrup.1st", false) ) /* topic 4 */
  794.     errorexit(missingFile);
  795.  
  796.   StartTopic("GUIDE Program", "GUIDE      ", "Popup Reference Engine.\n");
  797.   if ( CopyFile("int2guid.gui", true) ) /* topic 5 */
  798.     errorexit(missingFile);
  799.  
  800.   configure();
  801.  
  802.   indexed = 0;
  803.   indexNo = mainIndex;
  804.  
  805.   while ( RecognizedTopic() )
  806.     CopyTopic();
  807.  
  808.   Cleanup();
  809.  
  810.   exit(0);
  811. }
  812.  
  813. /* End of INT2GUID.C */
  814.